package spl.manager;

import java.io.File;
import java.io.IOException;

import java.util.Vector;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;


import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import spl.utils.GlobalLogger;

import dataStructure.Employee;



public class XMLParser{

	private String fXMLFileName;
	private Document fDom;
	private Vector<Employee> fEmployees;

	public XMLParser(String xmlFileName){
		this.fXMLFileName = xmlFileName;
		this.fEmployees = new Vector<Employee>();
		
		this.parseXmlFile();
	}


	public Vector<Employee> getParsedEmployees(){
		this.parseEmplyeeDocument();
		return this.fEmployees;
	}
	
	public int getRepresentationId() {
		try {
			Element inpRepElement = (Element) this.fDom.getElementsByTagName("InputRepresentation").item(0);
			
			String repId = inpRepElement.getAttribute("id");
			
			return Integer.parseInt(repId);
			
		}catch (NullPointerException e) {
			GlobalLogger.getLogger().warning("Got bad xml file");
		}

		return -1;
	}

	public void parseXmlFile(){
		//get the factory
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

		try {

			//Using factory get an instance of document builder
			DocumentBuilder db = dbf.newDocumentBuilder();
			//parse using builder to get fDom representation of the XML file
			this.fDom = db.parse(fXMLFileName);

		}catch(ParserConfigurationException pce) {
			pce.printStackTrace();
		}catch(SAXException se) {
			se.printStackTrace();
		}catch(IOException ioe) {
			ioe.printStackTrace();
		}
	}

	public int parseJobDocument(){
		//get the root element
		Element docEle = this.fDom.getDocumentElement();

		//get a nodelist of  elements
		NodeList nl = docEle.getElementsByTagName("JobRequest");
		
		if (nl.getLength() != 1)
			return -1;
		
		int repr = -1;
		try {
			repr = this.getIntValue((Element)nl.item(0), "InputRepresentation");
		} catch (NumberFormatException e) {
			System.err.println("Warning - Can't decode id");
			
		}
		return -1;
	}
	
	public void parseEmplyeeDocument(){
		//get the root element
		Element docEle = fDom.getDocumentElement();

		//get a nodelist of  elements
		NodeList nl = docEle.getElementsByTagName("Employee");
		if(nl != null && nl.getLength() > 0) {
			for(int i = 0 ; i < nl.getLength();i++) {

				//get the employee element
				Element el = (Element)nl.item(i);

				//get the Employee object
				Employee e = getEmployee(el);

				//add it to list
				fEmployees.add(e);
			}
		}
	}

	/**
	 * I take an employee element and read the values in, create
	 * an Employee object and return it
	 */
	private Employee getEmployee(Element empEl) {

		//for each <employee> element get text or int values of
		//name ,id, age and name
		String name = getTextValue(empEl,"Name");
		int id = getIntValue(empEl,"Id");
		int age = getIntValue(empEl,"Age");

		String type = empEl.getAttribute("type");

		//Create a new Employee with the value read from the xml nodes
		Employee e = new Employee(name,id,age,type);

		return e;
	}


	/**
	 * I take a xml element and the tag name, look for the tag and get
	 * the text content
	 * i.e for <employee><name>John</name></employee> xml snippet if
	 * the Element points to employee node and tagName is 'name' I will return John
	 */
	private String getTextValue(Element ele, String tagName) {
		String textVal = null;
		NodeList nl = ele.getElementsByTagName(tagName);
		if(nl != null && nl.getLength() > 0) {
			Element el = (Element)nl.item(0);
			textVal = el.getFirstChild().getNodeValue();
		}

		return textVal;
	}


	/**
	 * Calls getTextValue and returns a int value
	 */
	private int getIntValue(Element ele, String tagName) {
		//in production application you would catch the exception
		return Integer.parseInt(this.getTextValue(ele,tagName));
	}


	public void setRepId(int repId) {
		try {
			NodeList nl = this.fDom.getElementsByTagName("JobRequest");
			
			Element jr = (Element) nl.item(0);
			
			Element dstRep = this.fDom.createElement("OutputRepresentation");
			dstRep.setAttribute("id", Integer.toString(repId));
			
			jr.appendChild(dstRep);
			
		} catch (NullPointerException e) {
			throw e;
		}
	}
	
	public void dumpXML(File dst) throws TransformerException {
		TransformerFactory transformerFactory = TransformerFactory.newInstance();
		Transformer transformer = transformerFactory.newTransformer();
		DOMSource source = new DOMSource(this.fDom);
		StreamResult result = new StreamResult(dst);

		transformer.transform(source, result);
	}

}